#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>

#define msleep(ms) usleep(ms*1000)

/* 温度系数AD (temperature coefficient) */
#define TEMPERATURE_AD  "/sys/bus/iio/devices/iio:device0/in_voltage5_raw"

/* 前视灯开关 */
#define LED_SWITCH  "/sys/class/gpio/gpio75/value"

/* 前视灯亮度 */
#define LED_BRIGHTNESS  "/sys/devices/platform/leds/leds/light/brightness"

/* 1瓦特 */
#define ONEWATT 13

/* 位数 */
#define DIGIT   8

/* 电压 */
#define INPUT_VOLTAGE 3.3f

/**
 * __do_abnormal - exception handling.
 *	@str : function name
 */
void __do_abnormal(const char * str)
{
    printf("%s abnormal, program terminated...\n", str);
    exit(0);
}

/**
 * set_light - config led power.
 *	@value : power's scale
 */
int set_light(int value) {
    char buf[200] = {0};
    
    if (value > 0) {
        sprintf(buf, "echo %d > %s", value, LED_BRIGHTNESS);
        system(buf);
    }    

    return 0;
}

/**
 * is_open_light - led switch value.
 *	@none
 */
int is_open_light()
{
    FILE *fp = NULL;
    char data[8] = {0};

    fp = fopen(LED_SWITCH, "r");
    if (fp == NULL)  {
        printf("%s open fail...\n", LED_SWITCH);
    }

    fgets(data, 8, fp);
    printf("light was %s!\n", atoi(data) != 0 ? "on" : "off");
    
    fclose(fp);

    return atoi(data);
}

/**
 * obtian_temperature - temperature convert coefficient.
 *	@none
 */
float obtian_temperature()
{
    FILE *fp = NULL;
    char data[8] = {0};
    float voltage = 0.0f, resistance = 0.0f;
    int adc = 0;

    fp = fopen(TEMPERATURE_AD, "r");
    if (fp == NULL)  {
        printf("%s open fail...\n", TEMPERATURE_AD);
    }

    fgets(data, 8, fp);
    printf("temperature AD value %s", data);
    adc = atoi(data);
    fclose(fp);

    /* 通过ADC求电压 */
    /* Vref / (2^n-1) = Vresult / raw */
    /*
     * Vref 为标准电压  -> 1.8V
     * n 为 AD 转换的位数   -> 10
     * Vresult 为用户所需要的采集电压   ?
     * raw 为 AD 采集的原始数据 -> atoi(data)
     */    
    voltage = (INPUT_VOLTAGE * adc) / (1024 - 1);
    printf("voltage is %f\n", voltage);
    
    /* 求R2电阻值，利用分压公式 Vout = Vin * R2 / (R1 + R2) */
    /* Vin -> 1.8V, R1 = 10K */
    resistance = (voltage * 10) / (INPUT_VOLTAGE - voltage);
    printf("resistance is %f\n", resistance);   
    
    return resistance;
}

/**
 * obtian_led_power - led PWM value.
 *	@none
 */
float obtian_led_power()
{
    FILE *fp = NULL;
    char data[8] = {0};

    fp = fopen(LED_BRIGHTNESS, "r");
    if (fp == NULL)  {
        printf("%s open fail...\n", LED_BRIGHTNESS);
    }

    fgets(data, 8, fp);
    printf("led PWD value %d\n", atoi(data));
    
    fclose(fp);

    return atoi(data);
}

/**
 * is_temperature_high - temperature determine(温度测定).
 *	@none
 */
int is_temperature_high()
{
    float resistance = 0.0f; 
    double tempe = 0.0f;

    resistance = obtian_temperature();  

    /* T1 =1/(In(Rt/R)/B+1/T2) = 1/(log(r/10)/3435+1/(273.15+25)*/
    /*
     * T1、T2指的是K度即开尔文温度
     * K 273.15(绝对温度) + 摄氏温度 
     * B 3435K
     * T2 = (273.15 + 25)
     *
     * 等价:
     * 1/(log(resistance/10)/3435+1/(273.15+25))                # 10 为NTC R25阻值，即25度时为10K.
     */
    tempe = 1/(log((resistance-0.2)/10)/3435+1/(273.15+25))-273.15;
    printf("temperature = [%lf]\n", tempe);

    if (tempe > 65.0) {
        printf("temperature exceeds the limit((65.0))!\n");
        return 0;
    } 
    else if (tempe < 55.0) {
        printf("temperature below limit(55.0)!\n");
        return 1;
    } 
    else {
        printf("temperature normal...\n");
    }

    return -1;
}

/**
 * adjust - led operation.
 *	@none
 */
void adjust()
{
    int pwm = 0;     /* 130 is 10W, 104 is 8W */
    int temper_status = 0;
    static int ad_flag = 0; /* 控制降功耗不超过2W */

    printf("################ temperature adjust ################\n");

    pwm = obtian_led_power();
    temper_status = is_temperature_high();

    /* temperature high */
    if (!temper_status) {
        if (ad_flag == 0) {
            set_light(pwm - 13);
            ad_flag = 1;
        }
        else if (ad_flag == 1) {
            set_light(pwm - 13);
            ad_flag = 2;
        }
    }
    /* temperature low */
    else if (temper_status) {
        if (pwm >= 130) { 
            pwm = 130;
            set_light(pwm);
        } else {
            set_light(pwm + 13);
            ad_flag = 0;
        }
    }
}

/**
 * light_control - thread operation.
 *	@param : thread parameter
 */
void * light_control(void * param)
{
    static int count = 1;
	while (1) {
        printf("************ info ************\n");
        obtian_led_power();
        is_temperature_high();
        if (count % 60 == 0) {
            //adjust();
            count = 0;
        }
        msleep(1000);
        count++;
	}
}

/*
 * abstruct : main program.
 */
int main(int argc, char ** argv)
{
	int com;
	unsigned char buffer[] = "123";
	pthread_t lc_thread_id;

	void * ptr;
	pthread_attr_t attr;

	#if 1
	pthread_attr_init(&attr);

    is_open_light();

	lc_thread_id = 0;
	pthread_create(&lc_thread_id, &attr, light_control, NULL);
	msleep(1000);
	#endif	

	pthread_join(lc_thread_id, & ptr);

	return 0;
}

